#!usr/bin/env python
# -*- coding:utf-8 _*-
"""
@author:zhengxin
@file: serializers.py
@time: 2022/3/29  16:16
# @describe: 序列化类
"""
from rest_framework import serializers
from article.models import Article
from comment.serializers import CommentSerializer
from user_info.serializers import UserDetailSerializer
from article.models import Category, Tag
from article.models import Avatar


# class ArticleListSerializer(serializers.Serializer):
#     """
#     指定接口数据中各个字段的具体类型，自动对请求和响应中的数据进行序列化和反序列化的转换。
#     其底层实现逻辑已经由 DRF 框架封装好了
#     """
#     id = serializers.IntegerField(read_only=True)
#     title = serializers.CharField(read_only=True, max_length=100)
#     body = serializers.CharField(allow_blank=True)
#     created = serializers.DateTimeField()
#     updated = serializers.DateTimeField()

# 父类变成了 ModelSeerializer
# class ArticleListSerializer(serializers.ModelSerializer):
#     """
#     自动推断需要序列化的字段及类型
#     提供对字段数据的验证器的默认实现
#     提供了修改数据需要用到的 .create()、 .update()方法的默认实现
#     """
#     # HyperlinkedIdentityField 是 DRF 框架提供的超链接字段，只需要你在参数里提供路由的名称，它就自动帮你完成动态地址的映射。
#     url = serializers.HyperlinkedIdentityField(view_name="article:detail")
#     # read_only 参数设置为只读
#     author = UserDescSerializer(read_only=True)
#
#     class Meta:
#         model = Article
#         fields = [
#             # 'id',
#             'url',
#             'title',
#             'created',
#             'author'
#         ]
#         # # 指定只读字段
#         # read_only_fields = ['author']


# class ArticleDetailSerializer(serializers.ModelSerializer):
#     class Meta:
#         model = Article
#         # 使用所有字段
#         fields = '__all__'

class CategorySerializer(serializers.ModelSerializer):
    """ 分类的序列化器 """
    url = serializers.HyperlinkedIdentityField(view_name='category-detail')

    class Meta:
        model = Category
        fields = '__all__'
        read_only_fields = ['created']


class TagSerializer(serializers.HyperlinkedModelSerializer):
    """ 标签序列化器 """

    # 覆写 TagSerializer 的 create()/update() 方法：
    def check_tag_obj_exists(self, validated_data):
        text = validated_data('text')
        if Tag.objects.filter(text=text).exista():
            raise serializers.ValidationError(f'Tag with text {text} exists.')

    def create(self, validated_data):
        self.check_tag_obj_exists(validated_data)
        return super().create(validated_data)

    def update(self, instance, validated_data):
        self.check_tag_obj_exists(validated_data)
        return super().update(instance, validated_data)

    class Meta:
        model = Tag
        fields = '__all__'


class AvatarSerializer(serializers.ModelSerializer):
    """ 标题图-序列化器 """
    url = serializers.HyperlinkedIdentityField(view_name='avatar-detail')

    class Meta:
        model = Avatar
        fields = '__all__'


class ArticleBaseSerializer(serializers.HyperlinkedModelSerializer):
    id = serializers.IntegerField(read_only=True)
    # 设置为只读
    author = UserDetailSerializer(read_only=True)
    # category 的嵌套序列化字段
    category = CategorySerializer(read_only=True)
    # category 的 id 字段，用于创建/更新 category 外键,
    # write_only表示此字段仅需要可写；allow_null 表示允许将其设置为空；required 表示在创建 / 更新时可以不设置此字段。
    category_id = serializers.IntegerField(write_only=True, allow_null=True, required=False)
    # tag 字段
    tags = serializers.SlugRelatedField(queryset=Tag.objects.all(),
                                        many=True,
                                        required=False,
                                        slug_field='text')
    # 图片字段
    avatar = AvatarSerializer(read_only=True)
    avatar_id = serializers.IntegerField(
        write_only=True,
        allow_null=True,
        required=False
    )

    # 自定义错误信息
    default_error_messages = {
        'incorrect_avatar_id': 'Avatar with id {value} not exists.',
        'incorrect_category_id': 'Category with id {value} not exists.',
        'default': 'No more message here..'
    }

    def check_obj_exists_or_fail(self, model, value, message='defalut'):
        if not self.default_error_messages.get(message, None):
            message = 'default'
        if not model.objects.filter(id=value).exists() and value is not None:
            self.fail(message, value=value)

    # 验证图片id 是否存在-不存在则返回验证错误
    def validate_avatar_id(self, value):
         self.check_obj_exists_or_fail(
             model=Avatar,
             value=value,
             message='incorrect_avatar_id'
         )
         return value

    # cattegory_id 字段的验证器
    def validate_category_id(self, value):
        self.check_obj_exists_or_fail(
            model=Category,
            value=value,
            message='incorrect_category_id'
        )
        return value

    # 覆写方法，如果输入的标签不存在则创建它
    def to_internal_value(self, data):
        tags_data = data.get('tags')

        # isinstance() 确定标签数据是列表
        if isinstance(tags_data, list):
            for text in tags_data:
                if not Tag.objects.filter(text=text).exists():
                    Tag.objects.create(text=text)
        return super().to_internal_value(data)


class ArticleSerializer(ArticleBaseSerializer):
    """
    文章序列化器
    """
    class Meta:
        model = Article
        fields = '__all__'
        # 仅可写却不显示
        extra_kwargs = {'body': {'write_only': True}}


class ArticleCategoryDetailSerializer(serializers.ModelSerializer):
    """ 给分类详情的嵌套序列化器 """
    url = serializers.HyperlinkedIdentityField(view_name='article-detail')

    class Meta:
        model = Article
        fields = [
            'url',
            'title'
        ]


class CateoryDetailSerializer(serializers.ModelSerializer):
    """ 分类详情 """
    article = ArticleCategoryDetailSerializer(many=True, read_only=True)

    class Meta:
        model = Category
        fields = [
            'id',
            'title',
            'created',
            'articles'
        ]


class ArticleDetailSerializer(ArticleBaseSerializer):
    """ 文章详情-序列化器 """
    # 文章评论id
    id = serializers.IntegerField(read_only=True)
    # 文章评论
    comments = CommentSerializer(many=True, read_only=True)
    # 渲染后的正文
    body_html = serializers.SerializerMethodField()
    # 渲染后的目录
    toc_html = serializers.SerializerMethodField()

    def get_body_html(self, obj):
        return obj.get_md()[0]

    def get_toc_html(self, obj):
        return obj.get_md()[1]

    class Meta:
        model = Article
        fields = '__all__'
















